package com.ruoyi.system.controller;

import com.ruoyi.system.util.CommUtil;
import com.ruoyi.system.util.ResObject;
import com.ruoyi.system.domain.MyTask;
import org.flowable.engine.HistoryService;
import org.flowable.engine.RepositoryService;
import org.flowable.engine.RuntimeService;
import org.flowable.engine.TaskService;
import org.flowable.engine.history.HistoricActivityInstance;
import org.flowable.engine.history.HistoricProcessInstance;
import org.flowable.engine.repository.Deployment;
import org.flowable.engine.repository.ProcessDefinition;
import org.flowable.engine.runtime.Execution;
import org.flowable.engine.runtime.ProcessInstance;
import org.flowable.task.api.Task;
import org.flowable.task.api.history.HistoricTaskInstance;
import org.springframework.beans.BeanUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.PostMapping;
import org.springframework.web.bind.annotation.RequestBody;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RequestParam;
import org.springframework.web.bind.annotation.ResponseBody;
import org.springframework.web.bind.annotation.RestController;

import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;

@RestController
@RequestMapping("/flowable")
public class FlowableController {
	//RepositoryService查询部署和流程定义。挂起或者激活流程部署或者流程定义。大多数是处理一些静态信息
	//RepositoryService类是仓库服务类,仓库指的是流程定义文档的两个文件:bpmn文件和流程图片
    //ProcessEngine processEngine = Configuration.getProcessEngine();
    @Autowired
    private RepositoryService repositoryService;
    
    //启动一个流程实例
    @Autowired
    private RuntimeService runtimeService;
    
    //查询分配给某人或一组的任务,产生独立的任务,不依赖于任何流程实例的任务，流程实例需要等待一个外部触发,从而继续执行
    @Autowired
    private TaskService taskService;

    @Autowired
    private HistoryService historyService;

    @GetMapping("/deploy222")
    public ResObject de(@RequestParam("name") String name) {

        System.out.println(name);

        return new ResObject("success");
    }

    @GetMapping("/deploy")
    public ResObject deploy(String fileName) {
        //部署流程
        Deployment deploy = repositoryService.createDeployment().addClasspathResource(fileName).deploy();
        //查找部署流程的定义
        ProcessDefinition processDefinition = repositoryService.createProcessDefinitionQuery().deploymentId(deploy.getId()).singleResult();

        Map<String, Object> variables = new HashMap<>(16);
        variables.put("nextUser1", "张三");
        variables.put("nextUser2", "李四");
        variables.put("nextUser3", "王五");
        ProcessInstance processInstance = runtimeService.startProcessInstanceById(processDefinition.getId(), variables);

        return new ResObject(processInstance.getProcessInstanceId());
    }
    @ResponseBody
	@PostMapping(value="add")
    public String applyForLeave(String username, String days, String reason) {
        System.out.println(username+" "+days+" "+reason);
      //部署流程test-first.bpmn20.xml
        Deployment deploy = repositoryService.createDeployment().addClasspathResource("processes/test-first.bpmn20.xml").deploy();
        //查找部署流程的定义
        ProcessDefinition processDefinition = repositoryService.createProcessDefinitionQuery().deploymentId(deploy.getId()).singleResult();

		  Map<String, Object> variables = new HashMap<>(); 
		  variables.put("username", username); 
		  variables.put("days", days); 
		  variables.put("reason", reason);
		  variables.put("nextUser1", "辅导员");
	      variables.put("nextUser2", "学生工作处");
	      variables.put("nextUser3", "领导");
		  ProcessInstance processInstance = runtimeService.startProcessInstanceByKey("test-first-model-key",variables);
		  
		  System.out.println("提交成功："+processInstance.getProcessInstanceId()+" "+processInstance.getId());
		 
        return "添加成功!";
    }//add
    @ResponseBody
    //只返回任务id和name
    @GetMapping("/queryTask")
    public List<Map<String, Object>> queryMyTask(String assignee) {
    	//String assignee="学生工作处";
    	List<Map<String, Object>> listMap = new ArrayList<>();
        String processDefinitionKey = "test-first-model-key";
        List<Task> tasks = taskService.createTaskQuery()
                .taskAssignee(assignee)
                .processDefinitionKey(processDefinitionKey)
                .list();
        for(Task task:tasks) {
        	System.out.println("taskId:"+task.getId()+",taskName:"+task.getName());
        	System.out.println("********************");
        }
        String[] ps = { "id", "name"};
        for (Task pd : tasks) {
			Map<String, Object> map = CommUtil.obj2map(pd, ps);
			listMap.add(map);
		}
		return listMap;
        //return tasks;
    }
    @GetMapping("/apply")
    public String apply(String taskId,String assignee) {
        taskService.complete(taskId);
        return assignee;
    }
    @GetMapping("/find")
    public ResObject find(String assignee) {
        List<Task> tasks = taskService.createTaskQuery().taskAssignee(assignee).list();
        for(Task task:tasks) {
        	System.out.println("taskId:"+task.getId()+",taskName:"+task.getName());
        	System.out.println("********************");
        }
        List<MyTask> myTasks = new ArrayList<>(tasks.size());
        tasks.forEach(item -> {
            MyTask myTask = new MyTask();
            BeanUtils.copyProperties(item, myTask);
            myTasks.add(myTask);
        });
        return new ResObject(myTasks);
    }

    @GetMapping("/agree")
    public ResObject agree(String taskId) {
        taskService.complete(taskId);
        return new ResObject();
    }
    @ResponseBody
    @PostMapping(value="/reject")
    public ResObject reject(@RequestBody MyTask task) {
    	String processInstanceId=task.getProcessInstanceId();
    	String executionId=task.getExecutionId();
        if(processInstanceId==null||executionId==null) {
        	System.out.println("processInstanceId==null"+" "+executionId);
        }
    	
    	String currentActivityId = runtimeService.getActiveActivityIds(executionId).get(0);
        String lastActivityId = getLastActivityId(processInstanceId, currentActivityId);
        //回退了 流程
        runtimeService.createChangeActivityStateBuilder()
                .processInstanceId(processInstanceId)
                .moveActivityIdTo(currentActivityId, lastActivityId)
                .changeState();

        return new ResObject();
    }

    private String getLastActivityId(String processInstanceId, String currentActivityId) {

        List<HistoricActivityInstance> list = historyService.createHistoricActivityInstanceQuery()
                .processInstanceId(processInstanceId)
                .finished()
                .activityType("userTask")
                .orderByHistoricActivityInstanceStartTime().desc()
                .list();


        String lastActivityId = null;
        //找到上一个流程的 activityId
        for (int i=0; i<list.size(); i++) {
            HistoricActivityInstance activityInstance = list.get(i);
            if(activityInstance.getActivityId().equals(currentActivityId)) {
                lastActivityId = list.get(++i).getActivityId();
                break;
            }
        }

        if(lastActivityId == null) {
            lastActivityId = list.get(0).getActivityId();
        }

        return lastActivityId;
    }
    @GetMapping("rollbask")
    public String rollbaskTask(String taskId, String targetTaskKey) {
        Task currentTask = taskService.createTaskQuery().taskId(taskId).singleResult();
        if (currentTask == null) {
            return "节点不存在";
        }
        List<String> key = new ArrayList<>();
        key.add(currentTask.getTaskDefinitionKey());


        runtimeService.createChangeActivityStateBuilder()
                .processInstanceId(currentTask.getProcessInstanceId())
                .moveActivityIdsToSingleActivityId(key, targetTaskKey)
                .changeState();
        return "驳回成功...";
    }

    //   查找运行实例的状态:
    //方式一:
    public void queryProcessInstanceState(String processInstanceId) {
    ProcessInstance processInstance = runtimeService.createProcessInstanceQuery()
            .processInstanceId(processInstanceId)
            //.deploymentId()
            .singleResult();
    if (processInstance != null) {
        System.out.println("当前流程实例正在运行");
    } else {
        System.out.println("当前流程实例已经结束");
    }
    }
    //方式二:
    public void queryProcessInstanceState2() {
        String processInstanceId = "59501";
        HistoricProcessInstance historicProcessInstance = 
           historyService.createHistoricProcessInstanceQuery()
                .processInstanceId(processInstanceId).singleResult();
        if (historicProcessInstance.getEndTime() == null) {
            System.out.println("当前流程实例正在运行");
        } else {
            System.out.println("当前流程实例已经结束");
        }
    }
    //  查询执行实例
    public void createExecutionQuery() {
        List<Execution> executions = runtimeService.createExecutionQuery()
                .list();
        for (Execution execution : executions) {
            System.out.println(execution.getId() + "," + execution.getActivityId());
        }
   }
    //  查询历史流程实例:
    @GetMapping("history")
    public void createHistoricProcessInstanceQuery(String processInstanceId) {
        //String processInstanceId = "b1243ed5-9adb-11eb-990d-4e918044e5c7";
        HistoricProcessInstance hpi = historyService.createHistoricProcessInstanceQuery()
                .processInstanceId(processInstanceId).
                        singleResult();
        System.out.println("流程定义ID：" + hpi.getProcessDefinitionId());
        System.out.println("流程实例ID：" + hpi.getId());
        System.out.println("StartTime:"+hpi.getStartTime());
        System.out.println("StartActivityId:"+hpi.getStartActivityId());
        System.out.println("EndTime:"+hpi.getEndTime());
    }
    // 查询历史活动实例:
    public void createHistoricActivityInstanceQuery() {
        List<HistoricActivityInstance> list = 
            historyService.createHistoricActivityInstanceQuery()
                .list();
        for (HistoricActivityInstance hai : list) {
            System.out.println(hai.getId());
        }
    }
    // 查询历史任务实例:
    //select distinct RES.* from ACT_HI_TASKINST RES order by RES.ID_ asc
    public void createHistoricTaskInstanceQuery() {
        List<HistoricTaskInstance> list = historyService.createHistoricTaskInstanceQuery()
                .list();
    }
    // 获取流程实例运行节点:
    public void getActiveActivityIds() {
        String executionId = "77005";
        List<String> activeActivityIds = runtimeService.getActiveActivityIds(executionId);
    }
    /**
     * 生成流程图
     *
     * @param processId 任务ID
     */
    /*@GetMapping("/diagram/{processId}")
    public void genProcessDiagram(HttpServletResponse httpServletResponse,
                                  @PathVariable("processId") String processId) throws Exception {
        ProcessInstance pi = runtimeService.createProcessInstanceQuery().processInstanceId(processId).singleResult();

        //流程走完的不显示图
        if (pi == null) {
            return;
        }
        Task task = taskService.createTaskQuery().processInstanceId(pi.getId()).singleResult();
        //使用流程实例ID，查询正在执行的执行对象表，返回流程实例对象
        String InstanceId = task.getProcessInstanceId();
        List<Execution> executions = runtimeService
                .createExecutionQuery()
                .processInstanceId(InstanceId)
                .list();

        //得到正在执行的Activity的Id
        List<String> activityIds = new ArrayList<>();
        List<String> flows = new ArrayList<>();
        for (Execution exe : executions) {
            List<String> ids = runtimeService.getActiveActivityIds(exe.getId());
            activityIds.addAll(ids);
        }

        //获取流程图

        BpmnModel bpmnModel = repositoryService.getBpmnModel(pi.getProcessDefinitionId());
        ProcessEngineConfiguration engconf = processEngine.getProcessEngineConfiguration();
        ProcessDiagramGenerator diagramGenerator = engconf.getProcessDiagramGenerator();
        InputStream in = diagramGenerator.generateDiagram(bpmnModel, "png",
                activityIds, flows, "宋体","宋体","宋体",null,1.0, false);
        OutputStream out = null;
        byte[] buf = new byte[1024];
        int legth = 0;
        try {
            out = httpServletResponse.getOutputStream();
            while ((legth = in.read(buf)) != -1) {
                out.write(buf, 0, legth);
            }
        } finally {
            if (in != null) {
                in.close();
            }
            if (out != null) {
                out.close();
            }
        }
    }
    
 // 源码 www.1b23.com
    /*public byte[] createImage2(String processInstanceId) {
            //1.获取当前的流程实例
            ProcessInstance processInstance = runtimeService.createProcessInstanceQuery().processInstanceId(processInstanceId).singleResult();
            String processDefinitionId = null;
            List<String> activeActivityIds = null;
            //2.获取所有的历史轨迹对象
            List<HistoricActivityInstance> list = historyService.createHistoricActivityInstanceQuery()
                    .processInstanceId(processInstanceId).list();
            Map<String, HistoricActivityInstance> hisActivityMap = new HashMap<>();
            list.forEach(historicActivityInstance -> {
                if (!hisActivityMap.containsKey(historicActivityInstance.getActivityId())) {
                    hisActivityMap.put(historicActivityInstance.getActivityId(), historicActivityInstance);
                }
            });
            //3. 获取流程定义id和高亮的节点id
            if (processInstance != null) {
                //3.1. 正在运行的流程实例
                processDefinitionId = processInstance.getProcessDefinitionId();
                activeActivityIds = runtimeService.getActiveActivityIds(processInstanceId);
            } else {
                //3.2. 已经结束的流程实例
                HistoricProcessInstance historicProcessInstance = historyService.createHistoricProcessInstanceQuery().processInstanceId(processInstanceId).singleResult();
                processDefinitionId = historicProcessInstance.getProcessDefinitionId();
                activeActivityIds = new ArrayList<>();
                List<EndEvent> endEvents = bpmnModelService.findEndFlowElement(processDefinitionId);
                List<String> finalActiveActivityIds = activeActivityIds;
                endEvents.forEach(endEvent -> {
                    if (hisActivityMap.containsKey(endEvent.getId())) {
                        finalActiveActivityIds.add(endEvent.getId());
                    }
                });
            }
            //4. 获取流程定义的所有节点信息
            List<FlowNode> flowNodes = bpmnModelService.findFlowNodes(processDefinitionId);
            Map<String, FlowNode> activityMap = flowNodes.stream().collect(Collectors.toMap(FlowNode::getId, flowNode -> flowNode));
            List<String> highLightedFlows = new ArrayList<>();
            //5. 递归得到高亮线
            activeActivityIds.forEach(activeActivityId -> this.getHighLightedFlows(activityMap, hisActivityMap, activeActivityId, highLightedFlows, activeActivityId));
            //6. 获取bpmnModel对象
            BpmnModel bpmnModel = bpmnModelService.getBpmnModelByProcessDefId(processDefinitionId);
            //7. 生成图片流
            InputStream inputStream = flowProcessDiagramGenerator.generateDiagram(bpmnModel, activeActivityIds, highLightedFlows);
            //8. 转化成byte便于网络传输
            byte[] datas = IoUtil.readInputStream(inputStream, "image inputStream name");
            return datas;
        }*/
    /*
     * //www.1b23.com
private void getHighLightedFlows(Map<String, FlowNode> flowNodeMap,
            Map<String, HistoricActivityInstance> hisActivityMap,
            String activeActivityId,
            List<String> highLightedFlows,
            String oldActivityId) {
        FlowNode flowNode = flowNodeMap.get(activeActivityId);
        List<SequenceFlow> incomingFlows = flowNode.getIncomingFlows();
        for (SequenceFlow sequenceFlow : incomingFlows) {
            String sourceRefId = sequenceFlow.getSourceRef();
            if (hisActivityMap.containsKey(sourceRefId) && !oldActivityId.equals(sourceRefId)) {
                highLightedFlows.add(sequenceFlow.getId());
                this.getHighLightedFlows(flowNodeMap, hisActivityMap, sourceRefId, highLightedFlows, oldActivityId);
            } else {
　
　　　　　　　　　　if (hisActivityMap.containsKey(sourceRefId)){
　　　　　　　　　　　　　　highLightedFlows.add(sequenceFlow.getId());
　　　　　　　　　　}
　　　　　　　　　　break; 
	} } }
      */
}
